// 版权归Epic Games, Inc.所有。保留所有权利。

#pragma once

#include "EnhancedInputComponent.h"
#include "LyraInputConfig.h"

#include "LyraInputComponent.generated.h"

class UEnhancedInputLocalPlayerSubsystem;
class UInputAction;
class UObject;

/**
 * ULyraInputComponent
 * 用于使用输入配置数据资产管理输入映射和绑定的组件。
 */
UCLASS(Config = Input)
class ULyraInputComponent : public UEnhancedInputComponent
{
	GENERATED_BODY()

public:

	ULyraInputComponent(const FObjectInitializer& ObjectInitializer);

	/**
	 * 添加输入映射
	 * @param InputConfig 输入配置数据资产
	 * @param InputSubsystem 增强输入本地玩家子系统
	 */
	void AddInputMappings(const ULyraInputConfig* InputConfig, UEnhancedInputLocalPlayerSubsystem* InputSubsystem) const;
	/**
	 * 移除输入映射
	 * @param InputConfig 输入配置数据资产
	 * @param InputSubsystem 增强输入本地玩家子系统
	 */
	void RemoveInputMappings(const ULyraInputConfig* InputConfig, UEnhancedInputLocalPlayerSubsystem* InputSubsystem) const;

	/**
	 * 绑定原生动作
	 * @tparam UserClass 用户类类型
	 * @tparam FuncType 函数类型
	 * @param InputConfig 输入配置数据资产
	 * @param InputTag 输入标签
	 * @param TriggerEvent 触发事件
	 * @param Object 用户对象
	 * @param Func 回调函数
	 * @param bLogIfNotFound 是否在未找到时记录日志
	 */
	template<class UserClass, typename FuncType>
	void BindNativeAction(const ULyraInputConfig* InputConfig, const FGameplayTag& InputTag, ETriggerEvent TriggerEvent, UserClass* Object, FuncType Func, bool bLogIfNotFound);

	/**
	 * 绑定技能动作
	 * @tparam UserClass 用户类类型
	 * @tparam PressedFuncType 按下函数类型
	 * @tparam ReleasedFuncType 释放函数类型
	 * @param InputConfig 输入配置数据资产
	 * @param Object 用户对象
	 * @param PressedFunc 按下回调函数
	 * @param ReleasedFunc 释放回调函数
	 * @param BindHandles 绑定句柄数组
	 */
	template<class UserClass, typename PressedFuncType, typename ReleasedFuncType>
	void BindAbilityActions(const ULyraInputConfig* InputConfig, UserClass* Object, PressedFuncType PressedFunc, ReleasedFuncType ReleasedFunc, TArray<uint32>& BindHandles);

	/**
	 * 移除绑定
	 * @param BindHandles 绑定句柄数组
	 */
	void RemoveBinds(TArray<uint32>& BindHandles);
};

/**
 * 绑定原生动作的实现
 * @tparam UserClass 用户类类型
 * @tparam FuncType 函数类型
 * @param InputConfig 输入配置数据资产
 * @param InputTag 输入标签
 * @param TriggerEvent 触发事件
 * @param Object 用户对象
 * @param Func 回调函数
 * @param bLogIfNotFound 是否在未找到时记录日志
 */
template<class UserClass, typename FuncType>
void ULyraInputComponent::BindNativeAction(const ULyraInputConfig* InputConfig, const FGameplayTag& InputTag, ETriggerEvent TriggerEvent, UserClass* Object, FuncType Func, bool bLogIfNotFound)
{
	check(InputConfig); // 确保输入配置有效
	// 根据输入标签查找原生输入动作
	if (const UInputAction* IA = InputConfig->FindNativeInputActionForTag(InputTag, bLogIfNotFound))
	{
		BindAction(IA, TriggerEvent, Object, Func); // 绑定动作
	}
}

/**
 * 绑定技能动作的实现
 * @tparam UserClass 用户类类型
 * @tparam PressedFuncType 按下函数类型
 * @tparam ReleasedFuncType 释放函数类型
 * @param InputConfig 输入配置数据资产
 * @param Object 用户对象
 * @param PressedFunc 按下回调函数
 * @param ReleasedFunc 释放回调函数
 * @param BindHandles 绑定句柄数组
 */
template<class UserClass, typename PressedFuncType, typename ReleasedFuncType>
void ULyraInputComponent::BindAbilityActions(const ULyraInputConfig* InputConfig, UserClass* Object, PressedFuncType PressedFunc, ReleasedFuncType ReleasedFunc, TArray<uint32>& BindHandles)
{
	check(InputConfig); // 确保输入配置有效

	// 遍历所有技能输入动作
	for (const FLyraInputAction& Action : InputConfig->AbilityInputActions)
	{
		// 确保输入动作和标签有效
		if (Action.InputAction && Action.InputTag.IsValid())
		{
			// 如果提供了按下回调函数，绑定触发事件
			if (PressedFunc)
			{
				BindHandles.Add(BindAction(Action.InputAction, ETriggerEvent::Triggered, Object, PressedFunc, Action.InputTag).GetHandle());
			}

			// 如果提供了释放回调函数，绑定完成事件
			if (ReleasedFunc)
			{
				BindHandles.Add(BindAction(Action.InputAction, ETriggerEvent::Completed, Object, ReleasedFunc, Action.InputTag).GetHandle());
			}
		}
	}
}